//
//  LiveStreamsController.swift
//  App
//
//  Created by melvyn on 2018/8/18.
//

import Foundation
import Vapor
import FluentSQLite
import Pagination
import APNS

class LiveStreamsController: RouteCollection {
    
    func boot(router: Router) throws {
        
        let noAuth = router.grouped("lives")
        
        noAuth.get(use: index)
        noAuth.get(LiveStream.parameter, use: find)
        noAuth.get(LiveStream.parameter, "upload", use: upload)
        noAuth.get(LiveStream.parameter, "comments", use: comments)
        
        let bearer = noAuth.grouped(User.tokenAuthMiddleware())
        bearer.post(use: create)
        //        bearer.put(LiveStream.parameter, use: update)
        bearer.delete(LiveStream.parameter, use: delete)
    }
    
    func create(_ req: Request) throws -> EventLoopFuture<LiveStream.FormData> {
        return try req.content.decode(LiveStream.FormData.self).flatMap({
            
            let user = try req.requireAuthenticated(User.self)
            
            var model = $0
            
            let storage = try Utility.default.save(model.metadata, destination: imageURL)
            
            model.thumbnail = storage.0
            model.uid = try user.requireID()
            model.metadata = nil
            
            return model.save(on: req)
        })
    }
    
    func index(_ req: Request) throws -> EventLoopFuture<[LiveStream.Public]> {
        
        return try LiveStream.query(on: req)
            .join(\User.id, to: \LiveStream.uid)
            .paginate(for: req)
            .alsoDecode(User.Public.self)
            .all()
            .map({
                $0.map { .init(liveStream: $0.0, upload: $0.1) }
            })
    }
    
    func find(_ req: Request) throws -> EventLoopFuture<LiveStream.Public> {
        var trim_up: Bool = false
        var include_coms: Bool = false
        do {
            trim_up = try req.query.get(Bool.self, at: "trim_up")
            include_coms = try req.query.get(Bool.self, at: "include_coms")
        } catch _ {}
        
        var eventLoopFuture: EventLoopFuture<LiveStream.Public>
        
        if trim_up && include_coms {
            eventLoopFuture = try req.parameters.next(LiveStream.self)
                .flatMap({ stream in
                    stream.up.get(on: req)
                        .map(User.Public.init)
                        .map({ (stream, $0) })
                })
                .flatMap({ models in
                    try models.0.comments.query(on: req)
                        .all()
                        .map({ LiveStream.Public.init(liveStream: models.0, upload: models.1, comments: $0) })
                })
        } else if trim_up {
            eventLoopFuture = try req.parameters.next(LiveStream.self)
                .flatMap({ stream in
                    stream.up.get(on: req)
                        .map(User.Public.init)
                        .map({ LiveStream.Public.init(liveStream: stream, upload: $0) })
                })
        } else if include_coms {
            eventLoopFuture = try req.parameters.next(LiveStream.self)
                .flatMap({ stream in
                    try stream.comments.query(on: req)
                        .all()
                        .map({ LiveStream.Public.init(liveStream: stream, comments: $0) })
                })
        } else {
            eventLoopFuture = try req.parameters.next(LiveStream.self)
                .map({ LiveStream.Public.init(liveStream: $0) })
        }
        
        return eventLoopFuture
    }
    
    
    //    func update(_ req: Request) throws -> EventLoopFuture<LiveStream.Public> {
    //        return try req.parameters.next(LiveStream.self).flatMap({ oldValue in
    //            return try req.content.decode(LiveStream.FormData.self).flatMap({ newValue in
    //                return oldValue.update(with: newValue)
    //                    .save(on: req)
    //                    .map { LiveStream.Public.ini}
    //            })
    //        })
    //    }
    
    func delete(_ req: Request) throws -> EventLoopFuture<HTTPStatus> {
        return try req.parameters.next(LiveStream.self)
            .flatMap({
                $0.delete(on: req).transform(to: .ok)
            })
    }
    
    func upload(_ req: Request) throws -> EventLoopFuture<User> {
        return try req.parameters.next(LiveStream.self)
            .flatMap { $0.up.get(on: req) }
    }
    
    func comments(_ req: Request) throws -> EventLoopFuture<[Comment.Public]> {
        return try req.parameters.next(LiveStream.self)
            .flatMap({
                try $0.comments.query(on: req)
                    .join(\User.id, to: \Comment.uid)
                    .alsoDecode(User.Public.self)
                    .all()
            })
            .map({
                $0.map(Comment.Public.init)
            })
    }
    
//    func subscribe(_ req: Request) throws -> EventLoopFuture<HTTPStatus> {
//        return req.eventLoop.newPromise()
//    }
}
